import React, { Fragment, useState } from 'react';
import { NetworkStatus } from '@apollo/client';
import {
  Box,
  GridCarousel,
  GridItem,
  ListBase,
  makeToast,
  PaymentCard,
  SecondaryButton,
  Text,
  useViewport,
} from '@nova-hf/ui';
import { CardType } from '@nova-hf/ui/umd/ts/src/cards/PaymentCard/PaymentCard';
import { MainColorType } from '@nova-hf/ui/umd/ts/src/styles/vars.css';
import { ErrorBanner } from 'beta/components/error/ErrorBanner';
import AddPaymentCard from 'beta/containers/add-card/AddPaymentCard';
import Hradleid from 'beta/store/hradleid';
import { inject, observer } from 'mobx-react';
import { useRouter } from 'next/router';
import {
  PaymentTypeV2,
  useAddPaymentMethodMutation,
  useConnectToContractsMutation,
  useContractAvailablePaymentMethodsQuery,
  useContractPaymentMethodQuery,
  useCustomerNameQuery,
  usePaymentMethodsQuery,
} from 'typings/graphql';
import { formatCardExpiryDate } from 'utils/helpers';
import { useTranslation } from 'utils/i18n';

import { SettingsButtons } from '../components/SettingsButtons';

type PaymentMethodProps = {
  contractId?: string;
  contractIds?: string[];
  color?: MainColorType;
  shouldRedirect?: boolean;
  hradleid?: Hradleid;
};

const PaymentMethod = ({
  color,
  contractId,
  contractIds,
  shouldRedirect = true,
  hradleid,
}: PaymentMethodProps) => {
  const router = useRouter();
  const { isXLarge } = useViewport();
  const isDesktop = isXLarge;
  const { t } = useTranslation(['payments', 'stillingar', 'errors']);
  const customerId = router.query.customerId ?? '';
  const serviceId = router.query.serviceId ?? '';
  const [selectedCreditCardId, setSelectedCreditCardId] = useState('');
  const [selectedBankClaim, setSelectedBankClaim] = useState(false);
  const [showAddPaymentCard, setShowAddPaymentCard] = useState(false);
  const [canSubmit, setCanSubmit] = useState(false);

  const {
    data: paymentMethodsData,
    loading: paymentMethodsLoading,
    error: paymentMethodsError,
    refetch: paymentMethodsRefetch,
    networkStatus: paymentMethodsNetworkStatus,
  } = usePaymentMethodsQuery({
    variables: {
      input: {
        id: customerId.toString(),
      },
    },
  });

  const {
    data: contractPaymentMethodData,
    loading: contractPaymentMethodLoading,
    refetch: contractPaymentRefetch,
  } = useContractPaymentMethodQuery({
    variables: {
      input: {
        id: contractId ? contractId : '',
      },
    },
    skip: !contractId,
  });

  const currentPaymentMethod = contractPaymentMethodData?.contractPaymentMethod;

  const {
    data: availablePaymentMethodsData,
    loading: availablePaymentMethodsLoading,
    error: availablePaymentMethodsError,
  } = useContractAvailablePaymentMethodsQuery({
    variables: {
      input: {
        id: contractId ? contractId : '',
      },
    },
    skip: !contractId,
  });

  const { data: customerData } = useCustomerNameQuery({
    variables: {
      input: {
        id: customerId.toString(),
      },
    },
  });

  const customer = customerData?.customer;

  const isBankClaimAvailable = availablePaymentMethodsData?.availablePaymentMethods?.some(
    (availablePayementMethod) => availablePayementMethod === PaymentTypeV2.BankClaim,
  );

  const [addBankClaimPaymentMethod] = useAddPaymentMethodMutation({
    onCompleted: async (data) => {
      if (data?.addPaymentMethod?.id) setSelectedCreditCardId(data.addPaymentMethod?.id);
      onSubmitExistingPaymentMethod();
      await paymentMethodsRefetch();
    },
    onError: (error) => {
      if (error instanceof Error) makeToast.danger(t('bankClaim.addFail'), error.message);
    },
  });

  const [connectPaymentMethodToContract] = useConnectToContractsMutation({
    onCompleted: () => {
      contractPaymentRefetch();
      makeToast.success(t('card.changeSuccess'), '');

      if (contractIds) {
        hradleid?.incrementTrigger();
      }

      if (shouldRedirect) {
        serviceId
          ? router.push(`/beta/${customerId}/thjonustur/${serviceId}`)
          : router.push(`/beta/${customerId}/thjonustur`); // when alltSaman comes /beta/${customerId}/thjonustur/${contractId} has to be here as well
      }
    },
    onError: (error) => {
      if (error instanceof Error) makeToast.danger(t('card.changeFail'), error.message);
    },
  });

  const onSubmitExistingPaymentMethod = async () => {
    if (selectedCreditCardId) {
      await connectPaymentMethodToContract({
        variables: {
          input: {
            contractIds: contractId ? [contractId] : contractIds,
            paymentMethodId: selectedCreditCardId,
          },
        },
      });
    }
  };

  const onSubmitBankClaimPaymentMethod = async () => {
    if (selectedBankClaim && customerId && customer?.nationalId) {
      await addBankClaimPaymentMethod({
        variables: {
          input: {
            customerId: customerId.toString(),
            nationalId: customer.nationalId,
            type: PaymentTypeV2.BankClaim,
            cardCvc: '',
            cardExpiry: '',
            cardNumber: '',
          },
        },
      });
    }
  };

  const onSubmitNewCreditCard = async () => {
    await paymentMethodsRefetch();
    setShowAddPaymentCard(!showAddPaymentCard);
  };

  const bankClaimPaymentMethod = paymentMethodsData?.paymentMethods?.paymentmethods.filter(
    (bankClaim) =>
      bankClaim?.__typename === 'BankClaimPaymentMethod' &&
      bankClaim?.type === PaymentTypeV2.BankClaim,
  );

  const paymentMethods = paymentMethodsData?.paymentMethods?.paymentmethods;
  const uniquePaymentMethods = paymentMethods
    ? paymentMethods.filter((card, index, self) => {
        return self.findIndex((c) => c.id === card.id) === index;
      })
    : [];

  const onSelectingExistingPaymentMethod = (id: string) => {
    setCanSubmit(false);
    setSelectedCreditCardId(id);
    setSelectedBankClaim(false);
  };

  const onSelectedBankClaim = () => {
    setSelectedBankClaim(!selectedBankClaim);
    setCanSubmit(!canSubmit);
    setSelectedCreditCardId('');
  };

  const onToggleNewCreditCard = () => {
    setShowAddPaymentCard(!showAddPaymentCard);
    setSelectedCreditCardId('');
  };

  if (
    paymentMethodsLoading ||
    paymentMethodsError ||
    !paymentMethodsData ||
    (contractId && contractPaymentMethodLoading) ||
    (contractId && availablePaymentMethodsError) ||
    (contractId && availablePaymentMethodsLoading)
  )
    return (
      <>
        <ErrorBanner
          eyebrowTexts={[
            t('errors:settings.payment.eyebrows.1'),
            t('errors:settings.payment.eyebrows.2'),
            t('errors:settings.payment.eyebrows.3'),
          ]}
          titles={[
            t('errors:settings.payment.titles.1'),
            t('errors:settings.payment.titles.2'),
            t('errors:settings.payment.titles.3'),
          ]}
          descriptions={[
            t('errors:settings.payment.descriptions.1'),
            t('errors:settings.payment.descriptions.2'),
            t('errors:settings.payment.descriptions.3'),
          ]}
          icon="zap"
          color={color ?? 'attention'}
          showLoading={
            paymentMethodsLoading || paymentMethodsNetworkStatus === NetworkStatus.refetch
          }
          refetchButton={{
            text: t('errors:buttons.refresh'),
            icon: 'refresh',
            onClick: () => paymentMethodsRefetch(),
          }}
          loadingComponent={
            <>
              <ListBase isLoading gap={3} />
              <ListBase isLoading gap={3} />
              <ListBase isLoading />
            </>
          }
        />
      </>
    );

  return (
    <Box>
      <Box marginBottom={5}>
        <Text variant="pMediumBold">
          {showAddPaymentCard ? t('card.add') : t('card.yourCards')}
        </Text>
        <Box display="flex" justifyContent="flex-end" marginLeft="auto">
          <SecondaryButton
            colorScheme={color}
            icon={showAddPaymentCard ? 'creditcard' : 'add'}
            onClick={() => onToggleNewCreditCard()}
            text={showAddPaymentCard ? t('card.savedCards') : t('card.add')}
          />
        </Box>
      </Box>
      {showAddPaymentCard ? (
        <AddPaymentCard
          customerId={customerId.toString()}
          onConfirm={() => onSubmitNewCreditCard()}
          onCancel={() => onToggleNewCreditCard()}
          color={color}
        />
      ) : (
        <>
          <GridCarousel
            gridTemplate={{ sm: 2, xl: 4 }}
            numberOnSlide={isDesktop ? 4 : 2}
            noSlidesPadding
            backButtonHiddenTitle={t('grid.prev')}
            nextButtonHiddenTitle={t('grid.next')}
            color={color}
          >
            {isBankClaimAvailable && !bankClaimPaymentMethod?.length && (
              <GridItem>
                <PaymentCard
                  onClick={() => onSelectedBankClaim()}
                  boxShadow={canSubmit ? 'focused' : 'none'}
                  cardType="HEIMABANKI"
                  cardNumber={customer?.name?.split(' ')[0] ?? ''}
                  expiryDate={t('stillingar:payment.paymentMethod.bankclaim')}
                  color={color}
                  selectedText={t('bankClaim.inUse')}
                  isSelected={false}
                />
              </GridItem>
            )}
            {bankClaimPaymentMethod &&
              bankClaimPaymentMethod?.length > 0 &&
              bankClaimPaymentMethod?.map((bankClaim) => {
                return (
                  <GridItem key={bankClaim.id}>
                    <PaymentCard
                      onClick={() => onSelectingExistingPaymentMethod(bankClaim.id)}
                      boxShadow={selectedCreditCardId === bankClaim.id ? 'focused' : 'none'}
                      cardType="HEIMABANKI"
                      cardNumber={customer?.name?.split(' ')[0] ?? ''}
                      expiryDate={t('stillingar:payment.paymentMethod.bankclaim')}
                      color={color}
                      selectedText={t('bankClaim.inUse')}
                      isSelected={currentPaymentMethod?.id === bankClaim.id}
                    />
                  </GridItem>
                );
              })}
            {uniquePaymentMethods
              .filter((card) => card.id && card.__typename === 'CreditCardPaymentMethod')
              .map((card) => {
                return (
                  <Fragment key={card.id}>
                    {card.__typename === 'CreditCardPaymentMethod' && (
                      <GridItem>
                        <Box
                          borderStyle="solid"
                          borderColor={selectedCreditCardId === card.id ? 'pink' : 'grey300'}
                          borderWidth="2px"
                          borderRadius="medium"
                        >
                          <PaymentCard
                            onClick={() => onSelectingExistingPaymentMethod(card.id)}
                            boxShadow={selectedCreditCardId === card.id ? 'focused' : 'none'}
                            cardType={card.issuer as CardType}
                            cardNumber={card?.maskedNumber?.slice(-8) ?? ''}
                            expiryDate={formatCardExpiryDate(card.expiry ?? '')}
                            color={color}
                            selectedText={t('bankClaim.inUse')}
                            isSelected={currentPaymentMethod?.id === card.id}
                          />
                        </Box>
                      </GridItem>
                    )}
                  </Fragment>
                );
              })}
          </GridCarousel>
          <SettingsButtons
            confirmButton={{
              text: t('card.confirm'),
              colorScheme: color,
              icon: 'longArrowRight',
              isDisabled: !selectedCreditCardId && !selectedBankClaim && !canSubmit,
              onClick: () => {
                selectedCreditCardId && !canSubmit
                  ? onSubmitExistingPaymentMethod()
                  : onSubmitBankClaimPaymentMethod();
              },
            }}
          />
        </>
      )}
    </Box>
  );
};

export default inject('hradleid')(observer(PaymentMethod));
